package com.maxdu.labs.stt.activities;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.stt.R;
import com.maxdu.labs.stt.constants.Constants;
import com.maxdu.labs.stt.models.TPlan;
import com.maxdu.labs.stt.models.Training;
import com.maxdu.labs.stt.models.TrainingType;
import com.maxdu.labs.stt.models.UserVSTPlan;
import com.maxdu.labs.stt.models.db.UserVSTPlanDBHelper;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;

/*
Algorithm:
 1A/ get the list of people who are in this tplan
 1B/ get all trainings in this tplan
 	when 1A & 1B done: observer launchs 2/
 2/ trainings are sorted by userId. for each user, create his WeekResult object
 	2.1/ remove this user from all users (so at the end we know who didn't train
 3/ notifyDataSetChanged
 */

public class SeeTPlanWeeklyActivity extends Activity {

	private TPlan tplan;
	private ProgressBar loading;
	private TextView tplanNameTV;
	private TextView currentWeekTV;
	private Button addTrainingBtn;
	
	private List<WeekResult> weekResultList;
	
	private List<String> peopleInThisTraining;
	private List<Training> trainingsOfThisTPlan;
	private final TaskResultObservable taskOb = new TaskResultObservable();
	
	private ResultsAdapter adapter;
	private ListView weeklyResultsLV;
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.activity_see_tplan_weekly);
		
        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();

        if(bundle!=null)
        {
            tplan =(TPlan) bundle.get("tplan");
            if(tplan != null){
            	
        		//set title
                ActionBar actionBar = getActionBar();
                actionBar.setTitle(tplan.getName());
            	
            	Log.d(Constants.LOG_TAG,"tplanId == " + tplan.getId());
            	
            	loading = (ProgressBar) findViewById(R.id.progressBar1);
            	tplanNameTV = (TextView) findViewById(R.id.tv_tplan_name);
            	currentWeekTV = (TextView) findViewById(R.id.tv_current_week);
            	
            	tplanNameTV.setText(tplan.getName());
            	loading.setVisibility(View.VISIBLE);
            	
            	addTrainingBtn = (Button)findViewById(R.id.btn_add_training);
            	addTrainingBtn.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						Intent intent = new Intent(SeeTPlanWeeklyActivity.this, AddTrainingActivity.class);
						intent.putExtra("tplan", tplan);
						startActivity(intent);
					}
				});
            	
            	peopleInThisTraining = new ArrayList<String>();
            	trainingsOfThisTPlan = new ArrayList<Training>();
            	weekResultList = new ArrayList<WeekResult>();
            	weeklyResultsLV = (ListView)findViewById(R.id.lv_user_results);
            	
            	adapter = new ResultsAdapter(this,R.layout.row_weekly_results,weekResultList);
            	weeklyResultsLV.setAdapter(adapter);
            	
            	int week = 0;
            	
            	if(bundle.get("week") != null){
            		week = bundle.getInt("week");
            	}
            	
            	if (week == 0){
            		currentWeekTV.setText(getString(R.string.current_week));
            	}else{
            		//TODO do something better
            		currentWeekTV.setText("Week : " + week);
            	}
            	
	    		ResultObserver resultOb = new ResultObserver(taskOb);
	    		taskOb.addObserver(resultOb);
            	
            	//STEP 1A :: get users in this TPlan
	    		GetUsersInThisTPlanTask usersTask = new GetUsersInThisTPlanTask();
	    		usersTask.execute(tplan.getId());
            	
	    		//STEP 1B :: get all trainings for this TPlan
	    		GetTrainingsForThisTPlanTask trainingsTask = new GetTrainingsForThisTPlanTask();
	    		trainingsTask.execute(tplan.getId());
	    		
	        }else{
	        	loading.setVisibility(View.GONE);
	        	TextView somethingWentWrongTV = (TextView) findViewById(R.id.something_went_wrong);
	        	somethingWentWrongTV.setVisibility(View.VISIBLE);
	        	Log.e(Constants.LOG_TAG, "Error: SeeTPlanWeekly: we couldn't retrieve from intent the TPlan Object");
	        }
	    }else{
	    	loading.setVisibility(View.GONE);
	    	TextView somethingWentWrongTV = (TextView) findViewById(R.id.something_went_wrong);
	    	somethingWentWrongTV.setVisibility(View.VISIBLE);
	    	Log.e(Constants.LOG_TAG, "Error: SeeTPlanWeekly: we couldn't retrieve from intent the TPlan Object");
		}
	}
	
	private long getFirstDayOfTheWeek(){
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR,0);
		calendar.set(Calendar.MINUTE,0);
		calendar.set(Calendar.SECOND,0);
		while (calendar.get(Calendar.DAY_OF_WEEK) > calendar.getFirstDayOfWeek()+1) {
		    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of week.
		}
		
		return calendar.getTimeInMillis();
	}
	
	private long getLastDayOfTheWeek(){
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR,23);
		calendar.set(Calendar.MINUTE,59);
		calendar.set(Calendar.SECOND,59);
		while (calendar.get(Calendar.DAY_OF_WEEK) > calendar.getFirstDayOfWeek()+1) {
		    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of week.
		}
		calendar.add(Calendar.DATE, 6);
		
		return calendar.getTimeInMillis();
	}
	
	private void removeThisUserFromPeopleList(String userId){
		List<String> idsToRemove = new ArrayList<String>();
		
		for (String userIdCursor : peopleInThisTraining){
			if (userId != null && userId.equals(userIdCursor)){
				idsToRemove.add(userIdCursor);
			}
		}
		for (String userIdToRemove : idsToRemove){
			peopleInThisTraining.remove(userIdToRemove);
		}
	}
	
	private void fillResults(){
		if (peopleInThisTraining != null && peopleInThisTraining.size() > 0 
				&& trainingsOfThisTPlan != null){
			
			for (int i=0; i<trainingsOfThisTPlan.size(); i++){
			
				String tmpUserId = trainingsOfThisTPlan.get(i).getUserId();
				removeThisUserFromPeopleList(tmpUserId);
				WeekResult tmpweekResult = new WeekResult(tmpUserId, true);
				
				while(i < trainingsOfThisTPlan.size() && tmpUserId.equals(trainingsOfThisTPlan.get(i).getUserId())){
					Training training = trainingsOfThisTPlan.get(i);
					Calendar cal = Calendar.getInstance();
					cal.setTime(new Date(training.getDate()));
					
					int day = cal.get(Calendar.DAY_OF_WEEK);
					
					tmpweekResult.setWeek(day,training.getType());
					i++;
				}
				weekResultList.add(tmpweekResult);
			}
			Log.w(Constants.LOG_TAG,"weekResultList size of real users == " + weekResultList.size());
			
			for (String userWithNoTraining : peopleInThisTraining){
				WeekResult tmpweekResult = new WeekResult(userWithNoTraining, false);
				weekResultList.add(tmpweekResult);
			}
		}
	}
	
	private class GetUsersInThisTPlanTask extends AsyncTask<String, Void, Void>{

		@Override
		protected Void doInBackground(final String... params) {
			
        	ParseQuery<ParseObject> query = ParseQuery.getQuery(UserVSTPlanDBHelper.PARSE_DB_TABLENAME_USERVSTPLAN);
    		query.whereEqualTo(UserVSTPlanDBHelper.PARSE_DB_FIELD_TPLANID, params[0]);
    		query.whereEqualTo(UserVSTPlanDBHelper.PARSE_DB_FIELD_ACCEPTED, UserVSTPlan.INVITATION_ACCEPTED);
    		
    		query.findInBackground(new FindCallback<ParseObject>() {
    		    public void done(List<ParseObject> usersInThisTPlan, ParseException e) {
    		        if (e == null) {
    		        	if (usersInThisTPlan != null && usersInThisTPlan.size()> 0){
    		        		
    		        		Log.d(Constants.LOG_TAG,"we found [" + usersInThisTPlan.size() + "] users in this TPlan [" + params[0] +"]");
    		        		
    		        		for (final ParseObject userVSTrainingPO : usersInThisTPlan){
    		        			peopleInThisTraining.add(userVSTrainingPO.getString(Training.PARSE_DB_FIELD_USERID));
    		        		}
    		        		Log.w(Constants.LOG_TAG,"about to increment the Observer");
    		        		taskOb.increment();
    		        		
    		        	}else if(usersInThisTPlan == null){
    		        		Log.w(Constants.LOG_TAG, "we couldn't retrieve the Users (UserVSTPlan) for the current TPlan ["+ params[0] +"] :: users list is NULL");
    		        	}else{
    		        		Log.d(Constants.LOG_TAG, "we couldn't retrieve the Users (UserVSTPlan) for the current TPlan ["+ params[0] +"] :: users list is EMPTY");
    		        	}
    		        } else {
    		            Log.d(Constants.LOG_TAG, "Error: " + e.getMessage());
    		        }
    		    }
    		});
			return null;
		}
	}
	
	private class GetTrainingsForThisTPlanTask extends AsyncTask<String, Void, Void>{

		@Override
		protected Void doInBackground(final String... params) {
			
        	ParseQuery<ParseObject> query = ParseQuery.getQuery(Training.PARSE_DB_TABLENAME);
    		query.whereEqualTo(Training.PARSE_DB_FIELD_TPLANID, params[0]);
    		query.orderByAscending(Training.PARSE_DB_FIELD_USERID);
    		
    		query.whereGreaterThan(Training.PARSE_DB_FIELD_DATE, 1408510800000L);
    		query.whereLessThan(Training.PARSE_DB_FIELD_DATE, getLastDayOfTheWeek());
    		
    		query.findInBackground(new FindCallback<ParseObject>() {
    		    public void done(List<ParseObject> trainingsInThisTPlan, ParseException e) {
    		        if (e == null) {
    		        	if (trainingsInThisTPlan != null && trainingsInThisTPlan.size()> 0){
    		        		
    		        		Log.d(Constants.LOG_TAG,"we found [" + trainingsInThisTPlan.size() + "] trainings in this TPlan [" + params[0] +"]");
    		        		for (ParseObject training : trainingsInThisTPlan){
    		        			trainingsOfThisTPlan.add(new Training(training.getString(Training.PARSE_DB_FIELD_TPLANID),
    		        													training.getString(Training.PARSE_DB_FIELD_USERID),
    		        													training.getLong(Training.PARSE_DB_FIELD_DATE),
    		        													training.getInt(Training.PARSE_DB_FIELD_TRAINING_TYPE)));
    		        		}
    		        		taskOb.increment();
    		        	}else if(trainingsInThisTPlan == null){
    		        		loading.setVisibility(View.GONE);
    			        	TextView somethingWentWrongTV = (TextView) findViewById(R.id.something_went_wrong);
    			        	somethingWentWrongTV.setVisibility(View.VISIBLE);
    		        		Log.w(Constants.LOG_TAG,"We couldn't find the Trainings for this TPlan [" + params[0] + "]. Training list is NULL");
    		        	}else{
    		        		loading.setVisibility(View.GONE);
    		        		taskOb.increment(); //we want to display the results even if no one trained
    		        		Log.d(Constants.LOG_TAG,"We couldn't find the Trainings for this TPlan [" + params[0] + "]. Training list is EMPTY");
    		        	}
    		        } else {
    		            Log.d(Constants.LOG_TAG, "Error: " + e.getMessage());
    		        }
    		    }
    		});
			return null;
		}
	}
	private class TaskResultObservable extends Observable{
		private int count;
		
		TaskResultObservable(){
			this.count = 0;
		}
		public void increment() {
			count++;
			setChanged();
		    notifyObservers();
		}
		public int getCount() {
			return this.count;
		}
	}
	private class ResultObserver implements Observer
	{
	   private TaskResultObservable ov = null;
	   public ResultObserver(TaskResultObservable ov)
	   {
	      this.ov = ov;
	   }
	   public void update(Observable obs, Object obj)
	   {
	      if (obs == ov)
	      {
	         if (ov.count > 1){
	        	 fillResults();
	        	 loading.setVisibility(View.GONE);
	        	 adapter.notifyDataSetChanged();
	         }
	      }
	   }
	}

	private class WeekResult{
		private String userId;
		private int[] day = new int[]{-1,-1,-1,-1,-1,-1,-1};
		private boolean hasTrained;
		
		WeekResult(String userId, boolean hasTrained){
			this.userId = userId;
			this.hasTrained = hasTrained;
		}
		
		public boolean isHasTrained() {
			return hasTrained;
		}

		public String getUserId() {
			return userId;
		}

		public int[] getWeek() {
			return day;
		}
		public void setWeek(int day, int type) {
			switch (day) {
			case 0:
				this.day[0] = type;
				break;
			case 1:
				this.day[1] = type;
				break;
			case 2:
				this.day[2] = type;
				break;
			case 3:
				this.day[3] = type;
				break;
			case 4:
				this.day[4] = type;
				break;
			case 5:
				this.day[5] = type;
				break;
			case 6:
				this.day[6] = type;
				break;
			}
		}
	}

	private class ResultsAdapter extends ArrayAdapter<WeekResult>{

		List<WeekResult> weekResult;
		
		public ResultsAdapter(Context context, int resource,
				List<WeekResult> objects) {
			super(context, resource, objects);
			
			weekResult = objects;
		}
		
		@Override
	    public View getView(final int position, View convertView, ViewGroup parent) {
	        View view = convertView;
	        if (view == null) {
	        	LayoutInflater inflater = (LayoutInflater)getContext().getSystemService
	        		      (Context.LAYOUT_INFLATER_SERVICE);
	            view = inflater.inflate(R.layout.row_weekly_results, parent,false);
	        }

	        final WeekResult weekResult= weekResultList.get(position);
	        
            TextView userNameTV = (TextView) view.findViewById(R.id.tv_user_name);
            
            userNameTV.setText(weekResult.getUserId());
            
            if(weekResult.isHasTrained()){
	            for (int i=0; i<7; i++){
	            	if(weekResult.getWeek()[i] > -1 ){
	            		if (i == 0){
	            			ImageView mondayIcon = (ImageView) view.findViewById(R.id.image_monday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				mondayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				mondayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}else if (i == 1){
	            			ImageView tuesdayIcon = (ImageView) view.findViewById(R.id.image_tuesday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				tuesdayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				tuesdayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}else if (i == 2){
	            			ImageView wednesdayIcon = (ImageView) view.findViewById(R.id.image_wednesday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				wednesdayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				wednesdayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}else if (i == 3){
	            			ImageView thursdayIcon = (ImageView) view.findViewById(R.id.image_thursday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				thursdayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				thursdayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}else if (i == 4){
	            			ImageView fridayIcon = (ImageView) view.findViewById(R.id.image_friday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				fridayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				fridayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}else if (i == 5){
	            			ImageView saturdayIcon = (ImageView) view.findViewById(R.id.image_saturday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				saturdayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				saturdayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}else if (i == 6){
	            			ImageView sundayIcon = (ImageView) view.findViewById(R.id.image_sunday);
	            			if (weekResult.getWeek()[i] == TrainingType.TYPE_CLIMBING){
	            				sundayIcon.setImageResource(R.drawable.climbing_icon);
	            			}else if(weekResult.getWeek()[i] == TrainingType.TYPE_RUNNING){
	            				sundayIcon.setImageResource(R.drawable.running_icon);
	            			}
	            		}
	            	}
	            }
            }
	        return view;
	    }
	}
}


